package io2.nio.pipeline;

class HandlerContext {
    private Handler handler;
    private HandlerContext prev;
    private HandlerContext next;

    public HandlerContext(Handler handler) {
        this.handler = handler;
    }

    public void handle(Object obj) {
        handler.handle(this, obj);
    }

    public void runNext(Object obj) {
        if(next != null) {
            next.handle(obj);
        }
    }

    public void setPrev(HandlerContext prev) {
        this.prev = prev;
    }

    public void setNext(HandlerContext next) {
        this.next = next;
    }
}

@FunctionalInterface
interface Handler {
    void handle(HandlerContext context, Object obj);
}

class JannaPipeline {
    private HandlerContext head;
    private HandlerContext tail;

    public JannaPipeline() {
        head = new HeadHandlerContext();
        tail = head;
        head.setNext(tail);
        tail.setPrev(head);
    }

    /**
     * 添加处理器到pipeline的尾部
     * @param handler
     */
    public void addLast(Handler handler) {
        HandlerContext context = new HandlerContext(handler);
        tail.setNext(context);
        context.setPrev(tail);
        tail = context;
    }

    /**
     * 处理请求
     * @param obj
     */
    public void request(Object obj) {
        head.handle(obj);
    }

    private class HeadHandlerContext extends HandlerContext {
        public HeadHandlerContext() {
            super(null);
        }

        @Override
        public void handle(Object obj) {
            runNext(obj);
        }
    }
}

class Handler1 implements Handler {
    @Override
    public void handle(HandlerContext context, Object obj) {
        obj = obj.toString() + " [handler1]";
        context.runNext(obj);
    }
}

/**
 * 责任链模式 - 管道绑定多个处理器
 */
public class PipelineDemo {
    public static void main(String[] args) {
        JannaPipeline pipeline = new JannaPipeline();
        pipeline.addLast(new Handler1());
        pipeline.addLast((ctx, obj) -> {
            obj = obj.toString() + " [lambda handler]";
            ctx.runNext(obj);
        });
        pipeline.addLast(new Handler1());
        pipeline.addLast((ctx, obj) -> {
            System.out.println("receive message -> " + obj);
        });

        pipeline.request("Hello, world!");
    }
}
